package org.zuel.lkq.config;

import com.alibaba.druid.util.StringUtils;
import org.apache.shiro.authc.pam.FirstSuccessfulStrategy;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.zuel.lkq.component.CustomizedModularRealmAuthenticator;
import org.zuel.lkq.component.LoginWebSessionManager;
import org.zuel.lkq.component.ShiroAccessFilter;
import org.zuel.lkq.component.UserPasswordRealm;
import org.zuel.lkq.domain.Perm;
import org.zuel.lkq.service.AuthQueryService;

import javax.servlet.Filter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Configuration
public class ShiroConfig {

    private final AuthQueryService authQueryService;

    @Autowired
    public ShiroConfig(AuthQueryService authQueryService) {
        this.authQueryService = authQueryService;
    }

//    @Bean
//    public Realm userPhoneRealm() {
//        return new UserPhoneRealm();
//    }

    @Bean
    public Realm userRealm() {
        return new UserPasswordRealm();
    }

    /**
     * 配置认证策略
     */
    @Bean
    public CustomizedModularRealmAuthenticator customizedModularRealmAuthenticator() {
        CustomizedModularRealmAuthenticator authenticator = new CustomizedModularRealmAuthenticator();
        authenticator.setAuthenticationStrategy(new FirstSuccessfulStrategy());
        return authenticator;
    }

    @Bean
    public ShiroAccessFilter shiroAccessFilter() {
        return new ShiroAccessFilter();
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 获取匿名权限url
        List<Perm> perms = authQueryService.queryAnonPerms();
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        //开放匿名方法
        if(perms != null && perms.size() > 0) {
            perms.forEach(perm -> {
                if(!StringUtils.isEmpty(perm.getPermUrl())) {
                    filterChainDefinitionMap.put(perm.getPermUrl(), "anon");
                }});
        }
        filterChainDefinitionMap.put("/swagger-ui.html", "anon");
        filterChainDefinitionMap.put("/swagger-resources", "anon");
        filterChainDefinitionMap.put("/swagger-resources/configuration/security", "anon");
        filterChainDefinitionMap.put("/swagger-resources/configuration/ui", "anon");
        filterChainDefinitionMap.put("/v2/api-docs", "anon");
        filterChainDefinitionMap.put("/webjars/springfox-swagger-ui/**", "anon");
        filterChainDefinitionMap.put("/auth/register", "anon");
        filterChainDefinitionMap.put("/auth/login", "anon");
        filterChainDefinitionMap.put("/auth/login2", "anon");
        filterChainDefinitionMap.put("/auth/logout", "anon");
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        // 更新authc过滤器，鉴权失败返回信息不做重定向
        Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
        filters.put("authc", shiroAccessFilter());
        return shiroFilterFactoryBean;
    }

    @Bean
    public FilterRegistrationBean registration(ShiroAccessFilter filter) {
        FilterRegistrationBean registration = new FilterRegistrationBean(filter);
        registration.setEnabled(false);
        return registration;
    }

    @Bean
    public LoginWebSessionManager loginWebSessionManager() {
        return new LoginWebSessionManager();
    }

    @Bean
    public SimpleCookie cookie(){
        //  cookie的name,对应的默认是 JSESSIONID
        SimpleCookie cookie = new SimpleCookie("SHAREJSESSIONID");
        cookie.setHttpOnly(true);
        //  path为 / 用于多个系统共享JSESSIONID
        cookie.setPath("/");
        return cookie;
    }

    @Bean
    public ShiroRedis redisConfig(){
        return new ShiroRedis();
    }

    @Bean
    public JavaUuidSessionIdGenerator sessionIdGenerator(){
        return new JavaUuidSessionIdGenerator();
    }

    @Bean
    public RedisManager redisManager(){
        // crazycake 实现
        ShiroRedis redisConfig = redisConfig();
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(redisConfig.getHost());
        redisManager.setTimeout(redisConfig.getTimeout());
        if(!StringUtils.isEmpty(redisConfig.getPassword())) {
            redisManager.setPassword(redisConfig.getPassword());
        }
        return redisManager;
    }

    @Bean
    public RedisSessionDAO sessionDAO(){
        // crazycake 实现
        RedisSessionDAO sessionDAO = new RedisSessionDAO();
        // Session ID 生成器
        sessionDAO.setSessionIdGenerator(sessionIdGenerator());
        sessionDAO.setKeyPrefix("design:session:");
        sessionDAO.setRedisManager(redisManager());
        return sessionDAO;
    }

    @Bean
    public SessionManager sessionManager(){
        LoginWebSessionManager sessionManager = loginWebSessionManager();
        // 设置session超时
        sessionManager.setGlobalSessionTimeout(redisConfig().getTimeout());
        // 删除无效session
        sessionManager.setDeleteInvalidSessions(true);
        // 设置JSESSIONID
        sessionManager.setSessionIdCookie(cookie());
        // 设置sessionDAO
        sessionManager.setSessionDAO(sessionDAO());
        return sessionManager;
    }

    @Bean
    public RedisCacheManager redisCacheManager(){
        // crazycake 实现
        RedisCacheManager cacheManager = new RedisCacheManager();
        cacheManager.setRedisManager(redisManager());
        return cacheManager;
    }

    /**
     * 配置SecurityManager
     */
    @Bean
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm
        securityManager.setAuthenticator(customizedModularRealmAuthenticator());
        List<Realm> realms = new ArrayList<>();
        realms.add(userRealm());
        // realms.add(userPhoneRealm());
        securityManager.setRealms(realms);
        // 设置sessionManager
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }
}
